/*******************************************************************************
 * Copyright (c) 2013, 2014 UT-Battelle, LLC.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Initial API and implementation and/or initial documentation - Jay Jay Billings,
 *   Jordan H. Deyton, Dasha Gorin, Alexander J. McCaskey, Taylor Patterson,
 *   Claire Saunders, Matthew Wang, Anna Wojtowicz
 *******************************************************************************/
package org.eclipse.ice.client.widgets.grid;

import java.util.List;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.ice.client.widgets.grid.Cell.State;

/**
 * This class provides the "root" EditPart (rectangular) for the {@link Grid}
 * model. It is responsible for adding a {@link CellEditPart} to the Grid. It
 * must also add row and column labels when necessary.
 * 
 * @author Jordan H. Deyton
 * 
 */
public class GridEditPart extends AbstractGraphicalEditPart {

	/**
	 * The index offset from the first row generated by having column and row
	 * labels.
	 */
	private int columnLabelOffset;

	/**
	 * Whether or not to use the custom GridLayout or a Draw2D GridLayout.
	 */
	private boolean useCustomGridLayout = true;

	private static final int draw2dStyle = org.eclipse.draw2d.GridData.HORIZONTAL_ALIGN_FILL
			| org.eclipse.draw2d.GridData.GRAB_HORIZONTAL;

	/**
	 * Creates the root Figure for the Grid. This is a FreeformLayer that
	 * contains a grid of labels and {@link CellFigures}.
	 */
	@Override
	protected IFigure createFigure() {

		// Initialize the root figure. We use a FreeformLayer. FIXME - This was
		// in a few tutorials. We should find some links to explain why this is
		// important.
		Figure rootFigure = new FreeformLayer() {
		};
		rootFigure.setBackgroundColor(ColorConstants.white);
		rootFigure.setOpaque(true);

		// Get the grid model.
		Grid grid = ((Grid) getModel());

		// Get the total number of rows and columns, including labels.
		int totalRows = grid.rows + (grid.showColumnLabels ? 2 : 0);
		int totalColumns = grid.columns + (grid.showRowLabels ? 2 : 0);

		if (useCustomGridLayout) {

			// Set the layout of the root figure to our custom layout.
			GridLayout layout = new GridLayout(totalRows, totalColumns);
			rootFigure.setLayoutManager(layout);

			// Add the column labels and set the offset for Cells' GridData.
			columnLabelOffset = 0;
			if (grid.showColumnLabels) {

				// We need to account for row labels in the Labels' GridData.
				int offset = (grid.showRowLabels ? 1 : 0);

				// Add a Label for each column. Set its GridData accordingly.
				for (int column = 0; column < grid.columns; column++) {
					Label l = new Label(grid.getColumnLabel(column));
					GridData gridData = new GridData(column + offset);
					rootFigure.add(l, gridData);
				}

				// Set the offset used to pad the Cells' GridData indexes.
				columnLabelOffset = totalColumns;
			}

			// Add the row labels.
			if (grid.showRowLabels) {

				// We need to account for column labels in the Labels' GridData.
				int offset = (grid.showColumnLabels ? 1 : 0);

				// Add a Label for each row. Set its GridData accordingly.
				for (int row = 0; row < grid.rows; row++) {
					Label l = new Label(grid.getRowLabel(row));
					GridData gridData = new GridData(
							(row + offset) * totalColumns);
					rootFigure.add(l, gridData);
				}
			}
		} else {

			Figure figure;
			org.eclipse.draw2d.GridData gridData;

			org.eclipse.draw2d.GridLayout layout = new org.eclipse.draw2d.GridLayout(
					totalColumns, true);
			rootFigure.setLayoutManager(layout);

			// Add the column labels.
			if (grid.showColumnLabels) {
				// Add an empty placeholder in the top left.
				if (grid.showRowLabels) {
					figure = new Figure();
					gridData = new org.eclipse.draw2d.GridData(draw2dStyle);
					rootFigure.add(figure, gridData);
					figure.setBackgroundColor(ColorConstants.darkGray);
					figure.setOpaque(true);
				}

				for (int column = 0; column < grid.columns; column++) {
					Label label = new Label(grid.getColumnLabel(column));
					gridData = new org.eclipse.draw2d.GridData(draw2dStyle);
					rootFigure.add(label, gridData);
					label.setBackgroundColor(ColorConstants.darkBlue);
					label.setOpaque(true);
				}

				// Add an empty placeholder in the top right.
				if (grid.showRowLabels) {
					figure = new Figure();
					gridData = new org.eclipse.draw2d.GridData(draw2dStyle);
					rootFigure.add(figure, gridData);
					figure.setBackgroundColor(ColorConstants.darkGray);
					figure.setOpaque(true);
				}
			}
		}

		return rootFigure;
	}

	@Override
	protected void createEditPolicies() {
		// FIXME - EditPolicies are supposed to be used to display selection
		// feedback (e.g., a border with handles). Do we need one for the parent
		// (Grid)?
		return;
	}

	/**
	 * Gets a list of the child models (Cells) for the grid.
	 */
	@Override
	protected List<Cell> getModelChildren() {
		// Return the model's list of Cells.
		return ((Grid) getModel()).getCells();
	}

	/**
	 * Adds the child's Figure to the {@link #getContentPane() contentPane}. In
	 * this case, the childEditPart is a CellEditPart.
	 * 
	 * @see org.eclipse.gef.editparts.AbstractEditPart#addChildVisual(EditPart,
	 *      int)
	 */
	@Override
	protected void addChildVisual(EditPart childEditPart, int index) {
		// Get the IFigure that we need to add from the childEditPart.
		CellFigure cellFigure = (CellFigure) ((CellEditPart) childEditPart)
				.getFigure();

		// Only proceed if there's a Figure to add.
		if (cellFigure == null) {
			return;
		}

		// Get the grid model.
		Grid grid = (Grid) getModel();

		// If necessary, tell the CellFigure to show its label.
		if (grid.showCellLabels) {
			((CellEditPart) childEditPart).showLabel();
		}
		// Get the index of the Cell in its Grid.
		int i = ((Cell) childEditPart.getModel()).getIndex();

		Object gridData;
		IFigure contentPane = getContentPane();

		if (useCustomGridLayout) {
			// Compute the offset created by having row labels.
			int rowLabelOffset = (grid.showRowLabels ? i / grid.columns * 2 + 1
					: 0);

			// Create a new GridData constraint for the IFigure using the
			// offsets.
			gridData = new GridData(i + columnLabelOffset + rowLabelOffset);

			// Add the CellFigure to the rootFigure with the above constraint.
			contentPane.add(cellFigure, gridData);
		} else {
			int column = i % grid.columns;
			int row = i / grid.columns;
			// Add a row label if this is the first item in the row.
			if (column == 0 && grid.showRowLabels) {
				Label label = new Label(grid.getRowLabel(row));
				gridData = new org.eclipse.draw2d.GridData(draw2dStyle);
				contentPane.add(label, gridData);
				label.setBackgroundColor(ColorConstants.darkBlue);
				label.setOpaque(true);
			}

			// Add the CellFigure to the rootFigure with the above constraint.
			gridData = new org.eclipse.draw2d.GridData(draw2dStyle);
			contentPane.add(cellFigure, gridData);
			cellFigure.setBackgroundColor(ColorConstants.darkGreen);
			cellFigure.setState(State.DISABLED);

			if (column == grid.columns - 1) {
				// Add a placeholder after the figure if this is the last item
				// in the row.
				if (grid.showRowLabels) {
					Figure figure = new Figure();
					gridData = new org.eclipse.draw2d.GridData(draw2dStyle);
					contentPane.add(figure, gridData);
					figure.setBackgroundColor(ColorConstants.darkGray);
					figure.setOpaque(true);
				}

				// Add a placeholder *row* if this is the last figure in the
				// grid.
				if (row == grid.rows - 1 && grid.showColumnLabels) {
					Figure figure = new Figure();
					gridData = new org.eclipse.draw2d.GridData(draw2dStyle);
					// ((org.eclipse.draw2d.GridData) gridData).horizontalSpan =
					contentPane.add(figure, gridData);
					figure.setBackgroundColor(ColorConstants.lightGray);
					figure.setOpaque(true);
				}
			}
		}

		return;
	}
}
